# -*- codeing = utf-8 -*-
# 

# 2/16 11:23
# 
# @File :movieApi.py
# #Desc :这个是电影接口的文件

import operator
import pymysql
from pymysql.cursors import DictCursor
from dbutils.pooled_db import PooledDB

from flask import Blueprint, request
from sqlalchemy import func
from sqlalchemy.sql import label

from algorithm import ItemCF, UserCF
from algorithm import MF
from algorithm import GraphX  # 正确导入GraphX模块
from base.code import ResponseCode, ResponseMessage
from base.core import db
from base.response import ResMsg
from models.comments import Comment, comment_schema
from models.model import chart_data
from models.movie import getWords, Movie, movie_schema
import random
import logging  # 确保logging导入在顶部

# Blueprint的作用就是一个前缀，相当于前端访问下面的接口的时候地址前都会加上movie
# 如  http://localhost:5000/movie/getWordCut 这样
# 好处就是很容易区分这个接口是在哪个模块下的，逻辑很清晰
movieBp = Blueprint("movie", __name__)

# 创建数据库连接池
pool = PooledDB(
    creator=pymysql,
    maxconnections=6,
    mincached=2,
    maxcached=5,
    blocking=True,
    host='localhost',
    user='root',
    password='123456',
    database='flask_douban_comment',
    charset='utf8mb4',
    cursorclass=DictCursor
)

def get_db_connection():
    return pool.connection()

# 分词接口，调用Jieba分词，给前端的词云图提供数据
@movieBp.route('/getWordCut', methods=["GET"])
def getWordCut():
    res = ResMsg()
    result = getWords()
    res.update(code=ResponseCode.SUCCESS, data=result)
    return res.data

# 搜索，这个搜索是给电影库用的，带了关键词这个参数
@movieBp.route('/get', methods=["GET"])
def get():
    res = ResMsg()
    keyword = request.args.get('keyword')
    if keyword is None:
        keyword = ""
    
    # Get all movies matching the keyword, ordered by score
    query = db.session.query(Movie).filter(Movie.name.like('%' + keyword + '%')).order_by(Movie.douban_score.desc())
    
    # Get total count for pagination
    total_count = query.count()
    
    # Get all results
    result = query.all()
    data = movie_schema.dump(result)
    
    res.update(code=ResponseCode.SUCCESS, data={"movies": data, "total": total_count})
    return res.data

# 热门--根据评分
@movieBp.route('/getHot', methods=["GET"])
def getHot():
    res = ResMsg()
    # 返回评分最高的20部电影，这样前端可以选择显示前10部
    result = db.session.query(Movie).order_by(Movie.douban_score.desc()).all()[:20]
    # 使用Marshmallow来对结果封装json
    data = movie_schema.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=data)
    return res.data

# 推荐 这个只是获取评分高的科幻电影，不是真实的推荐接口，目前前端应该没有调用这个接口
@movieBp.route('/getRec', methods=["GET"])
def getRec():
    res = ResMsg()
    result = db.session.query(Movie).filter(Movie.genres.like('%科幻%')).order_by(Movie.douban_score.desc()).all()[:4]
    data = movie_schema.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=data)
    return res.data

@movieBp.route('/getChart1', methods=["GET"])
def getChart1():
    res = ResMsg()
    all = []
    type_data = {}
    types = request.args.get('types', '').split(',')
    if not types or types[0] == '':
        types = ['动作', '科幻', '爱情', '喜剧', '剧情', '悬疑']
    
    ranges = [('1900', '1950'), ('1950', '1960'), ('1960', '1970'), ('1970', '1980'), ('1980', '1990'),
              ('1990', '2000'), ('2000', '2010'), ('2010', '2020'), ('2020', '2030')]
              
    for r in ranges:
        cnt = db.session.query(Movie).filter(Movie.year >= r[0], Movie.year < r[1]).count()
        all.append(dict(name=r[0] + '-' + r[1], value=cnt))
        
        for t in types:
            if t not in type_data:
                type_data[t] = []
            type_cnt = db.session.query(Movie).filter(
                Movie.genres.like('%' + t + '%'),
                Movie.year >= r[0],
                Movie.year < r[1]
            ).count()
            type_data[t].append(dict(name=r[0] + '-' + r[1], value=type_cnt))
    
    res.update(code=ResponseCode.SUCCESS, data=dict(all=all, types=type_data))
    return res.data

# 面积图接口
@movieBp.route('/getAreaChart', methods=["GET"])
def getAreaChart():
    res = ResMsg()
    kh = []
    ranges = [('1900', '1970'), ('1970', '1990'), ('1990', '2000'), ('2000', '2010'), ('2010', '2020')]
    for r in ranges:
        khcnt = db.session.query(Movie).filter(Movie.year >= r[0], Movie.year < r[1]).count()
        chart3 = dict(name=r[0] + '-' + r[1], value=khcnt)
        kh.append(chart3)
    # data = chart_data.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=dict(kh=kh))
    return res.data

#
@movieBp.route('/getChart2', methods=["GET"])
def getChart2():
    res = ResMsg()
    datas = []
    for i in range(2001, 2021):
        cnt = db.session.query(Movie).filter(Movie.year == i).count()
        chart = dict(name=i, value=cnt)
        datas.append(chart)
    res.update(code=ResponseCode.SUCCESS, data=datas)
    return res.data


@movieBp.route('/getChart3', methods=["GET"])
def getChart3():
    res = ResMsg()
    result = db.session.query(Movie.year.label('name'), func.count('*').label('value')).group_by(Movie.year).order_by(
        Movie.year.asc()).all()
    datas = chart_data.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=datas)
    return res.data

# 查询各类型电影的数量，给出排名
@movieBp.route('/getTypeRank', methods=["GET"])
def getTypeRank():
    res = ResMsg()
    types = ['惊悚', '古装', '武侠', '冒险', '喜剧', '恐怖', '犯罪', '历史', '歌舞', '纪录片', '动画', '科幻', '西部', '战争', '家庭', '传记', '悬疑',
             '儿童', '灾难', '奇幻', '剧情', '同性', '动作', '运动', '音乐', '情色', '爱情']
    datas = []
    for t in types:
        cnt = db.session.query(Movie).filter(Movie.genres.like('%' + t + '%')).count()
        chart = dict(name=t, value=cnt)
        datas.append(chart)
    datas = sorted(datas, key=operator.itemgetter('value'), reverse=True)

    res.update(code=ResponseCode.SUCCESS, data=dict(datas=datas))
    return res.data

# 查询各个国家电影的数量，给世界地图使用
@movieBp.route('/getNationRank', methods=["GET"])
def getNationRank():
    res = ResMsg()
    nations = ['摩纳哥', '西班牙', '印度', '比利时', '塞浦路斯', '英国', '冒险', '韩国', '希腊', '奥地利', '意大利', '动画', '德国', '泰国', '喜剧', '澳大利亚',
               '中国台湾', '巴西', '中国香港', '墨西哥', '加拿大', '匈牙利', '中国大陆', '瑞典', '新西兰', '卡塔尔', '捷克', '瑞士', '南非', '法国', '伊朗',
               '黎巴嫩', '阿联酋', '日本', '悬疑', '约旦', '爱尔兰', '波兰', '丹麦', '美国', '阿根廷', '荷兰']
    datas = []
    for t in nations:
        cnt = db.session.query(Movie).filter(Movie.regions.like('%' + t + '%')).count()
        chart = dict(name=t, value=cnt)
        datas.append(chart)
    datas = sorted(datas, key=operator.itemgetter('value'), reverse=True)

    res.update(code=ResponseCode.SUCCESS, data=dict(datas=datas))
    return res.data

# 这个代码暂时不用，注释掉
# @movieBp.before_request
# def init_session():
#     db.session = db.session.session_factory()

# 给出各个类型的评分，给散点图提供数据 （评分分析）
@movieBp.route('/getTypeRate', methods=["GET"])
def getTypeRate():
    res = ResMsg()
    types = ['剧情','爱情', '喜剧',  '冒险', '犯罪']
    datas = []
    for t in types:
        data = []
        movies = db.session.query(Movie).filter(Movie.genres.like('%' + t + '%')).all()
        for m in movies:
            rateData = []
            rateData.append(int(m.year))
            rateData.append(m.douban_score)
            data.append(rateData)
        datas.append(data)
    res.update(code=ResponseCode.SUCCESS, data=dict(datas=datas, labels=types))
    return res.data

# 是时间轴图提供数据，查询各个国家在2000-2021电影的出品情况
@movieBp.route('/getTimeLine', methods=["GET"])
def getTimeLine():
    res = ResMsg()
    types = ['美国', '英国', '日本', '中国香港', '中国大陆', '法国', '德国', '韩国', '意大利', '加拿大','中国台湾','澳大利亚','西班牙','印度','瑞士','新西兰']
    datas = []
    for y in range(2000, 2021):
        yearData = []
        for t in types:
            cnt = db.session.query(Movie).filter(Movie.year==y, Movie.regions.like('%' + t + '%')).count()
            yearData.append(cnt)
        datas.append(yearData)

    res.update(code=ResponseCode.SUCCESS, data=dict(datas=datas))
    return res.data

def get_user_rating_count(uid):
    """获取用户评分数量"""
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute('SELECT COUNT(*) as cnt FROM tb_rate WHERE uid = %s', (uid,))
        result = cursor.fetchone()
        return result['cnt'] if result else 0
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()

def get_random_active_user():
    """获取一个随机的活跃用户(uid 1-19)"""
    try:
        conn = get_db_connection()
        cursor = conn.cursor()
        # 获取评分数量前19的用户
        cursor.execute('''
            SELECT uid, COUNT(*) as rating_count 
            FROM tb_rate 
            GROUP BY uid 
            ORDER BY rating_count DESC 
            LIMIT 19
        ''')
        active_users = [row['uid'] for row in cursor.fetchall()]
        if active_users:
            return random.choice(active_users)
        return 1  # 如果没有找到活跃用户，返回uid=1
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()

# Flask 推荐算法接口（基于itemCF）
@movieBp.route('/getRecomendation', methods=["GET"])
def getRecomendation():
    userId = request.args.get('userId', type=int)
    res = ResMsg()
    rating_count = get_user_rating_count(userId)
    if rating_count < 5:
        userId = get_random_active_user()
    try:
        datas = ItemCF.recommend(userId)
        # 兜底1：UserCF
        if not datas:
            datas = UserCF.recommend(userId, top_n=5)
        # 兜底2：MF
        if not datas:
            datas = MF.recommend(userId, top_n=5)
        # 兜底3：GraphX
        if not datas:
            datas = GraphX.recommend(userId, top_n=5)
        if not datas:
            res.update(code=ResponseCode.SUCCESS, data={"datas": []})
            return res.data
        movie_ids = [iid for iid, _ in datas]
        movies = db.session.query(Movie).filter(Movie.id.in_(movie_ids)).all()
        movie_map = {m.id: m for m in movies}
        ordered_movies = [movie_map[mid] for mid in movie_ids if mid in movie_map]
        data = movie_schema.dump(ordered_movies)
        res.update(code=ResponseCode.SUCCESS, data={"datas": data})
    except Exception as e:
        logging.error(f"Error in getRecomendation: {e}")
        res.update(code=ResponseCode.FAIL, msg="推荐失败")
    finally:
        db.session.close()
    return res.data

# Flask 推荐算法接口（基于userCF）
@movieBp.route('/getRecomendation2', methods=["GET"])
def getRecomendation2():
    userId = request.args.get('userId', type=int)
    res = ResMsg()
    try:
        recs = UserCF.recommend(userId, top_n=5)
        if not recs:
            res.update(code=ResponseCode.SUCCESS, data={"datas": []})
            return res.data
        movie_ids = [iid for iid, _ in recs]
        movies = db.session.query(Movie).filter(Movie.id.in_(movie_ids)).all()
        movie_map = {m.id: m for m in movies}
        ordered_movies = [movie_map[mid] for mid in movie_ids if mid in movie_map]
        data = movie_schema.dump(ordered_movies)
        res.update(code=ResponseCode.SUCCESS, data={"datas": data})
    except Exception as e:
        logging.error(f"Error in getRecomendation2: {e}")
        res.update(code=ResponseCode.FAIL, msg="推荐失败")
    finally:
        db.session.close()
    return res.data

# 查询影评数据的接口
@movieBp.route('/getComments', methods=["POST"])
def getComments():
    res = ResMsg()
    try:
        data = request.json or {}
        douban_id = data.get('douban_id')
        if not douban_id:
            res.update(code=ResponseCode.FAIL, msg="缺少douban_id")
            return res.data
        comments = db.session.query(Comment).filter(Comment.douban_id == douban_id).all()
        data = comment_schema.dump(comments)
        res.update(code=ResponseCode.SUCCESS, data=data)
    except Exception as e:
        logging.error(f"Error in getComments: {e}")
        res.update(code=ResponseCode.FAIL, msg="获取评论失败")
    return res.data

# 这个函数非常关键，由于数据库的连接数是有限的，所以在操作完之后，一定要关闭db连接
# 这个方法可以在请求完之后自动关闭连接，这样就不需要每个接口里手动写关闭连接接口
@movieBp.after_request
def close_session(response):
    db.session.close()
    return response

@movieBp.route('/getSciFiAnalysis', methods=["GET"])
def getSciFiAnalysis():
    res = ResMsg()
    
    # 获取所有科幻电影
    scifi_movies = db.session.query(Movie).filter(Movie.genres.like('%科幻%')).all()
    
    # 评分分布
    rating_dist = {
        "0-6": 0, "6-7": 0, "7-8": 0, "8-9": 0, "9-10": 0
    }
    
    # 混合类型统计
    genre_combinations = {}
    
    # 关键词统计
    keywords = {}
    
    for movie in scifi_movies:
        # 计算评分分布
        score = float(movie.douban_score)
        if score < 6:
            rating_dist["0-6"] += 1
        elif score < 7:
            rating_dist["6-7"] += 1
        elif score < 8:
            rating_dist["7-8"] += 1
        elif score < 9:
            rating_dist["8-9"] += 1
        else:
            rating_dist["9-10"] += 1
            
        # 统计混合类型
        genres = movie.genres.split(',')
        for genre in genres:
            if genre.strip() != '科幻':
                key = f"科幻+{genre.strip()}"
                if key not in genre_combinations:
                    genre_combinations[key] = {
                        "count": 0,
                        "total_score": 0,
                        "avg_score": 0
                    }
                genre_combinations[key]["count"] += 1
                genre_combinations[key]["total_score"] += float(movie.douban_score)
                genre_combinations[key]["avg_score"] = round(
                    genre_combinations[key]["total_score"] / genre_combinations[key]["count"], 
                    2
                )
        
        # 统计关键词（这里用标题中的词作为示例）
        for word in movie.name.split():
            if len(word) > 1:  # 忽略单字符
                if word not in keywords:
                    keywords[word] = 0
                keywords[word] += 1
    
    # 处理混合类型数据
    genre_combinations = {
        k: v for k, v in sorted(
            genre_combinations.items(), 
            key=lambda x: x[1]["count"], 
            reverse=True
        )[:10]  # 只取前10个最常见组合
    }
    
    # 处理关键词数据
    keywords = {
        k: v for k, v in sorted(
            keywords.items(), 
            key=lambda x: x[1], 
            reverse=True
        )[:20]  # 只取前20个最常见关键词
    }
    
    result = {
        "total_movies": len(scifi_movies),
        "rating_distribution": rating_dist,
        "genre_combinations": genre_combinations,
        "keywords": keywords
    }
    
    res.update(code=ResponseCode.SUCCESS, data=result)
    return res.data

# 热门动漫--根据评分
@movieBp.route('/getHotAnime', methods=["GET"])
def getHotAnime():
    res = ResMsg()
    # 查询包含"动画"类型的电影，按评分排序
    result = db.session.query(Movie).filter(Movie.genres.like('%动画%')).order_by(Movie.douban_score.desc()).all()[:20]
    # 使用Marshmallow来对结果封装json
    data = movie_schema.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=data)
    return res.data

# 获取指定类别的评分最高的电影
@movieBp.route('/getTopByGenre', methods=["GET"])
def getTopByGenre():
    res = ResMsg()
    genre = request.args.get('genre', '')
    
    if genre == '最新':
        # 如果是最新分类，返回2025年评分最高的电影
        result = db.session.query(Movie).filter(Movie.year == '2025').order_by(Movie.douban_score.desc()).all()[:10]
    else:
        # 保持原有逻辑不变
        if not genre:  # 如果没有指定类别，返回所有电影中评分最高的
            result = db.session.query(Movie).order_by(Movie.douban_score.desc()).all()[:10]
        else:  # 返回指定类别中评分最高的
            result = db.session.query(Movie).filter(
                Movie.genres.like('%' + genre + '%')
            ).order_by(Movie.douban_score.desc()).all()[:10]
    
    data = movie_schema.dump(result)
    res.update(code=ResponseCode.SUCCESS, data=data)
    return res.data

@movieBp.route('/rating/distribution', methods=["GET"])
def getRatingDistribution():
    res = ResMsg()
    try:
        # 查询所有电影的评分并按评分分组统计数量
        result = db.session.query(
            Movie.douban_score.label('rating'),
            func.count(Movie.id).label('count')
        ).group_by(Movie.douban_score).order_by(Movie.douban_score.asc()).all()
        
        # 转换为前端需要的格式
        data = [{"rating": str(r.rating), "count": r.count} for r in result if r.rating is not None]
        
        res.update(code=ResponseCode.SUCCESS, data=data)
    except Exception as e:
        print("获取评分分布数据失败:", str(e))
        res.update(code=ResponseCode.FAIL, msg="获取评分分布数据失败")
    
    return res.data

# 更复杂的基于图的推荐算法接口 graphX
@movieBp.route('/getGraphXRec', methods=["GET"])
def getGraphXRec():
    userId = request.args.get('userId', type=int)
    res = ResMsg()
    try:
        datas = GraphX.recommend(userId, top_n=5)
        # 如果GraphX推荐为空，直接用MF兜底
        if not datas:
            datas = MF.recommend(userId, top_n=5)
        if not datas:
            res.update(code=ResponseCode.SUCCESS, data={"datas": []})
            return res.data
        movie_ids = [iid for iid, _ in datas]
        movies = db.session.query(Movie).filter(Movie.id.in_(movie_ids)).all()
        movie_map = {m.id: m for m in movies}
        ordered_movies = [movie_map[mid] for mid in movie_ids if mid in movie_map]
        data = movie_schema.dump(ordered_movies)
        res.update(code=ResponseCode.SUCCESS, data={"datas": data})
    except Exception as e:
        logging.error(f"Error in getGraphXRec: {e}")
        res.update(code=ResponseCode.FAIL, msg="推荐失败")
    finally:
        db.session.close()
    return res.data

@movieBp.route('/getMFRec', methods=["GET"])
def getMFRec():
    userId = request.args.get('userId', type=int)
    res = ResMsg()
    try:
        recs = MF.recommend(userId, top_n=5)
        if not recs:
            res.update(code=ResponseCode.SUCCESS, data={"datas": []})
            return res.data
        # 直接返回recs（已经是电影信息字典列表）
        res.update(code=ResponseCode.SUCCESS, data={"datas": recs})
    except Exception as e:
        logging.error(f"Error in getMFRec: {e}")
        res.update(code=ResponseCode.FAIL, msg="推荐失败")
    finally:
        db.session.close()
    return res.data

@movieBp.route('/rate', methods=["POST"])
def rate_movie():
    res = ResMsg()
    conn = None
    cursor = None
    try:
        data = request.json
        uid = data.get('uid')
        iid = data.get('iid')
        rate = data.get('rate')
        
        if not all([uid, iid, rate]):
            res.update(code=ResponseCode.FAIL, msg="Missing required parameters")
            return res.data
            
        # 验证电影ID是否存在
        movie = db.session.query(Movie).filter(Movie.id == iid).first()
        if not movie:
            res.update(code=ResponseCode.FAIL, msg="Invalid movie ID")
            return res.data
            
        conn = get_db_connection()
        cursor = conn.cursor()
        
        # 生成唯一ID：基于用户ID和电影ID的组合
        # 例如：用户ID=20，电影ID=4719，那么评分ID就是204719
        rating_id = int(str(uid) + str(iid))
        
        # 检查是否已经评分过
        cursor.execute('SELECT id FROM tb_rate WHERE uid=%s AND iid=%s', (uid, iid))
        existing = cursor.fetchone()
        
        if existing:
            # 更新已有评分，使用已存在的ID
            cursor.execute('UPDATE tb_rate SET rate=%s WHERE uid=%s AND iid=%s', (rate, uid, iid))
        else:
            # 插入新评分，使用生成的ID
            cursor.execute('INSERT INTO tb_rate (id, uid, iid, rate) VALUES (%s, %s, %s, %s)', 
                         (rating_id, uid, iid, rate))
        
        conn.commit()
        res.update(code=ResponseCode.SUCCESS, msg="Rating saved successfully")
    except Exception as e:
        print("保存评分失败:", str(e))
        if conn:
            try:
                conn.rollback()
            except:
                pass
        res.update(code=ResponseCode.FAIL, msg="Failed to save rating")
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()
    return res.data

@movieBp.route('/rate', methods=["GET"])
def get_user_rating():
    res = ResMsg()
    conn = None
    cursor = None
    try:
        uid = request.args.get('uid')
        iid = request.args.get('iid')
        
        if not all([uid, iid]):
            res.update(code=ResponseCode.FAIL, msg="Missing required parameters")
            return res.data
            
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute('SELECT rate FROM tb_rate WHERE uid=%s AND iid=%s', (uid, iid))
        rating = cursor.fetchone()
        
        if rating:
            res.update(code=ResponseCode.SUCCESS, data={"rate": rating['rate']})
        else:
            res.update(code=ResponseCode.SUCCESS, data=None)
    except Exception as e:
        print("获取评分失败:", str(e))
        res.update(code=ResponseCode.FAIL, msg="Failed to get rating")
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()
    return res.data

@movieBp.route('/saveFeedback', methods=["POST"])
def saveFeedback():
    res = ResMsg()
    conn = None
    cursor = None
    try:
        data = request.json or {}
        user_id = data.get('user_id')
        algorithm = data.get('algorithm')
        
        # 参数验证
        if not all([user_id, algorithm]):
            res.update(code=ResponseCode.FAIL, msg="参数不完整")
            return res.data
            
        # 获取原始数据库连接
        conn = db.engine.raw_connection()
        cursor = conn.cursor()
        
        # 检查用户是否已经提交过反馈
        cursor.execute("SELECT id FROM tb_recommend WHERE user_id = %s", (user_id,))
        existing = cursor.fetchone()
        
        if existing:
            # 如果已存在，更新反馈
            cursor.execute("UPDATE tb_recommend SET algorithm = %s WHERE user_id = %s", 
                         (algorithm, user_id))
        else:
            # 如果不存在，插入新反馈
            cursor.execute("INSERT INTO tb_recommend (user_id, algorithm) VALUES (%s, %s)",
                         (user_id, algorithm))
        
        # 提交事务
        conn.commit()
        res.update(code=ResponseCode.SUCCESS, msg="反馈已保存")
        
    except Exception as e:
        print("保存反馈失败:", str(e))  # 添加错误日志
        if conn:
            conn.rollback()
        res.update(code=ResponseCode.FAIL, msg="保存失败")
    finally:
        # 确保关闭游标和连接
        if cursor:
            cursor.close()
        if conn:
            conn.close()
            
    return res.data

@movieBp.route('/getAlgorithmStats', methods=["GET"])
def getAlgorithmStats():
    res = ResMsg()
    conn = None
    cursor = None
    try:
        # 获取原始数据库连接
        conn = db.engine.raw_connection()
        cursor = conn.cursor()
        
        # 分别统计每个算法的数量
        stats = {}
        
        # 查询 ItemCF 数量
        cursor.execute("SELECT COUNT(*) FROM tb_recommend WHERE algorithm = 'ItemCF'")
        stats['ItemCF'] = cursor.fetchone()[0]
        
        # 查询 UserCF 数量
        cursor.execute("SELECT COUNT(*) FROM tb_recommend WHERE algorithm = 'UserCF'")
        stats['UserCF'] = cursor.fetchone()[0]
        
        # 查询 GraphX 数量
        cursor.execute("SELECT COUNT(*) FROM tb_recommend WHERE algorithm = 'GraphX'")
        stats['GraphX'] = cursor.fetchone()[0]
        
        # 查询 MF 数量
        cursor.execute("SELECT COUNT(*) FROM tb_recommend WHERE algorithm = 'MF'")
        stats['MF'] = cursor.fetchone()[0]
        
        print("各算法统计结果:", stats)  # 添加调试日志
        res.update(code=ResponseCode.SUCCESS, data=stats)
        
    except Exception as e:
        print("获取算法统计失败:", str(e))
        res.update(code=ResponseCode.FAIL, msg="获取统计数据失败")
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()
            
    return res.data
